#include "barter_market.hpp"
#include "city.hpp"
#include "foreach.hpp"
#include "game_logic.hpp"
#include "gamemap.hpp"
#include "merchant.hpp"
#include "tile.hpp"
#include "tile_logic.hpp"
#include "unit.hpp"
#include "world.hpp"

void begin_turn(world& w)
{
	for(int x = 0; x != w.map().width(); ++x) {
		for(int y = 0; y != w.map().height(); ++y) {
			const hex::location loc(x, y);
			hex::tile_ptr t(w.map().get_tile(loc));

			if(t->city()) {
				t->city()->new_turn(w);
				t->city()->prepare_trades(w);
				t->process_occupations(w);
			}

			const unit_list& units = w.units_on_tile(loc);
			foreach(const unit_ptr& u, units) {
				u->new_turn();
			}
		}
	}

	execute_merchant_trades(w);
}

void end_turn(world& w, hex::gamemap& map, migrations_list& migrations)
{
	w.weather_next_turn();

	barter_market mkt;
	std::map<hex::location, int> ratings;
	hex::location adj[6];

	for(int x = 0; x != map.width(); ++x) {
		for(int y = 0; y != map.height(); ++y) {
			const hex::location loc(x, y);
			hex::tile_ptr t(map.get_tile(loc));
			t->end_turn(w);
			if(t->city()) {
				t->city()->end_turn(w);
				t->city()->fill_jobs(w);
			}
		}
	}

	//migrate due to having taken a job.
	for(int x = 0; x != map.width(); ++x) {
		for(int y = 0; y != map.height(); ++y) {
			const hex::location loc(x, y);
			hex::tile_ptr t(map.get_tile(loc));
			std::vector<citizen_ptr>::iterator c = t->citizens().begin();
			while(c != t->citizens().end()) {
				if((*c)->has_job() && (*c)->job()->tile() != t.get()) {
					(*c)->job()->tile()->citizens().push_back(*c);
					c = t->citizens().erase(c);
				} else {
					++c;
				}
			}
		}
	}


	for(int x = 0; x != map.width(); ++x) {
		for(int y = 0; y != map.height(); ++y) {
			const hex::location loc(x, y);
			hex::tile_ptr t(map.get_tile(loc));
			t->place_orders(mkt);
			mkt.resolve_market();
			mkt.clear();

			if(t->empty() == false && t->citizens().back()->has_job() == false && t->citizens().back()->get_occupation() == NULL) {
				const int rating = citizen::rate_tile(*map.get_tile(loc));
				int highest_rating = 0;
				int best_index = -1;
				hex::get_adjacent_tiles(loc, adj);
				for(int n = 0; n != 6; ++n) {
					if(!map.is_loc_on_map(adj[n])) {
						continue;
					}
					const int new_rating = citizen::rate_tile(*map.get_tile(adj[n]));
					if(best_index == -1 || new_rating > highest_rating) {
						highest_rating = new_rating;
						best_index = n;
					}
				}

				if(highest_rating > rating && best_index >= 0) {
					migrations.push_back(std::pair<hex::location,hex::location>(loc, adj[best_index]));
				}
			}
		}
	}

	typedef std::pair<hex::location,hex::location> migration_pair;
	foreach(const migration_pair& migration, migrations) {
		map.get_tile(migration.first)->migrate_to(*map.get_tile(migration.second));
	}
}
